package com.nifostasky.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nifostasky.constant.CacheConstant;
import com.nifostasky.dao.UserDao;
import com.nifostasky.entity.User;
import com.nifostasky.service.UserService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * 用户表(User)表服务实现类  注解形式
 *
 * @author makejava
 * @since 2021-09-26 11:08:49
 */
@Service("userAnnotationService")
/**
 * //如果没有此注解;则每个redis相关注解都需要加上 cacheNames={"user_cache"}
 * @Cacheable(cacheNames={"user_cache"},key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'",unless = "#result.size() == 0")
 * @CacheEvict(cacheNames={"user_cache"},key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'")
 */
@CacheConfig(cacheNames = CacheConstant.USER_CACHE_NAME)
public class UserAnnotationServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
    /**
     * 1 @CacheConfig
     * @Cacheable()里面都有一个value＝“xxx”的属性，这显然如果方法多了，写起来也是挺累的，如果可以一次性声明完
     * 那就省事了， 所以，有了@CacheConfig这个配置，
     * @CacheConfig is a class-level annotation that allows to share the cache names，
     * 如果你在你的方法写别的名字，那么依然以方法的名字为准。
     *
     * 2 @Cacheable
     * @Cacheable(value="myCache")，这个注释的意思是，当调用这个方法的时候，会从一个名叫myCache 的缓存中查询，
     * 如果没有，则执行实际的方法（即查询数据库），并将执行的结果存入缓存中，
     * 否则返回缓存中的对象。
     *
     * 3 @CachePut
     * @CachePut 的作用 主要针对方法配置，能够根据方法的请求参数对其结果进行缓存，
     * 和 @Cacheable 不同的是，它每次都会触发真实方法的调用。
     *
     * 4 @CacheEvict
     * @CachEvict 的作用 主要针对方法配置，能够根据一定的条件对缓存进行清空。
     * // 清空当前cache name下的所有key
     * @CachEvict(allEntries = true)
     *
     * 5 @Caching
     * @Caching可以使注解组合使用,比如根据id查询用户信息,查询完的结果为{key = id,value = userInfo},
     * 但我们现在为了方遍,想用用户的手机号,邮箱等缓存对应用户的信息,这时候我们就要使用@Caching。
     * 例:
     *
     * @Caching(put = {
     * @CachePut(value = "user", key = "#user.id"),
     * @CachePut(value = "user", key = "#user.username"),
     * @CachePut(value = "user", key = "#user.email")
     * })
     * public User getUserInfo(User user){
     *     ...
     * return user;
     * }
     *
     */


    /**
     * 先查询缓存中是否存在 key ;
     * 如果存在: 则直接返回key中的值即可;无需执行方法;
     * 如果key不存在: 则执行方法;并将返回值缓存到redis中;
     * @return
     */
    @Override
    @Cacheable(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'",unless = "#result.size() == 0")
    public List<User> queryAll() {
        return baseMapper.selectList(new QueryWrapper<User>());
    }

    /**
     * 先查询缓存中是否存在 key ;
     * 如果存在: 则直接返回key中的值即可;无需执行方法;
     * 如果key不存在: 则执行方法;并将返回值缓存到redis中;
     * 注:
     *      #userId 是参数名
     *      #result 是返回值
     * unless是表示如果满足这个条件 则不缓存到redis中
     * @return
     */
    @Override
    @Cacheable(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId", unless = "#result == null")
    public User getUserInfo(Long userId) {
        User user = Objects.nonNull(userId)? baseMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getId,userId)) : null;
        return user;
    }

    /**
     * 执行增加操作时,删除缓存中 保存查询全部信息 的key;
     *                  因为这些信息过时了;
     * @param user
     */
    @Override
    @CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'")
    public void add(User user) {
        baseMapper.insert(user);
    }

    /**
     * 执行更新操作时,删除缓存中 保存查询全部信息 的key;
     *              删除缓存中 保存对应用户信息 的key;
     *             因为这些信息过时了;
     * @param user
     */
    @Override
    @Caching(evict = {
            @CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'"),
            @CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #user.id")
            })
    public void update(User user) {
        baseMapper.updateById(user);
    }

    /**
     * 执行删除操作时; 删除缓存中 保存查询全部信息 的key;
     *               删除缓存中 保存对应用户信息 的key;
     * @param userId
     */
    @Override
    @Caching(evict = {
            @CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'"),
            @CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId")
            })
    public void delete(Long userId) {
        baseMapper.deleteById(userId);
    }
}
